package ec.fugu.amf;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

/**
 * AmfMessage 
 * 
 * The Message class encapsulates either an entire request package or an entire result package; including an AMF enveloppe
 * 
 * @author deathUser 
 */
public class AmfMessage {
	//private Object[] bodies;
	private Vector bodies;
	private Vector headers;
	private int encoding = AmfConstants.AMF0;
	private int clientType = 0;
	private DataOutputStream outputStream;
	private DataInputStream inputStream;
	
	public AmfMessage(){
		this.bodies = new Vector();
		this.headers = new Vector();
	}
	
	public void serialize(DataOutputStream stream) throws IOException{
		this.outputStream = stream;
		outputStream.write(AmfConstants.AMF3_UNDEFINED);
		outputStream.write(this.encoding);
		outputStream.writeShort(this.headers.size());
		Amf0Serializer serializer = new Amf0Serializer(stream);
		Enumeration e = this.headers.elements();
		while(e.hasMoreElements()){
			AmfHeader header = (AmfHeader)e.nextElement();
			serializer.writeString(header.getName());
			stream.writeBoolean(header.isRequred());
            stream.writeInt(-1);
            serializer.writeAMFData(header.getValue(),null);

		}
		outputStream.writeShort(this.bodies.size());
		e = this.bodies.elements();
		while(e.hasMoreElements()){
			AmfBody body = (AmfBody)e.nextElement();
			outputStream.writeUTF(body.getTarget());
			outputStream.writeUTF(body.getResponse());
            stream.writeInt(-1);
            switch(this.encoding){
            	case AmfConstants.AMF0: serializer.writeAMFData(body.getData(), null);
            							break;
            	case AmfConstants.AMF3: serializer.writeAMFData(new Amf3Wrapper(body.getData()), null);
            							break;
            }
		}
	}

	public void deserialize(DataInputStream stream) throws IOException{
		this.headers = new Vector();
		this.bodies = new Vector();
		this.inputStream = stream;
		this.inputStream.read();
		this.clientType = this.inputStream.read();
		if(this.clientType==AmfConstants.AMF0){
			//Do nothing
		}
		Amf0Deserializer deserializer = new Amf0Deserializer(this.inputStream);
		int totalHeaders = this.inputStream.readShort();
		for(int i=0; i<totalHeaders; i++){
			String name = this.inputStream.readUTF();
			boolean required = this.inputStream.readBoolean();
			Object value = deserializer.readAmfData(null);
			AmfHeader header = new AmfHeader(name, value, required);
			this.headers.addElement(header);
		}
		int totalBodies = this.inputStream.readShort();
		for(int i=0; i<totalBodies; i++){
			String target="";
			try {
				target = this.inputStream.readUTF();
			} catch (Exception e){
				break;
			}
			String response = this.inputStream.readUTF();
			int length = this.inputStream.readInt(); //ignore length
			Object data = deserializer.readAmfData(null);
			if(data instanceof Amf3Wrapper)
				this.encoding = AmfConstants.AMF3;
			AmfBody body = new AmfBody(target, response, length, data);
			this.bodies.addElement(body);
		}
		
	}
	public Vector getBodies(){
		return this.bodies;
	}

	public Vector getHeaders(){
		return this.headers;
	}

	public void addBody(AmfBody body){
		this.bodies.addElement(body);
	}

	public void addHeader(AmfHeader header){
		this.headers.addElement(header);
	}
	
	public void setEncoding(int encoding){
		this.encoding = encoding;
	}

	public int getEncoding(){
		return this.encoding;
	}
}